{
 "cells": [
  {
   "cell_type": "raw",
   "metadata": {
    "raw_mimetype": "text/restructuredtext"
   },
   "source": [
    ".. _media::\n",
    "\n",
    "|\n",
    "|\n",
    "\n",
    "Download This Notebook: :download:`Media.ipynb`\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Media\n",
    "\n",
    "## Introduction\n",
    "\n",
    "\n",
    "**skrf** supports some basic circuit simulation based on transmission line models. Network creation is accomplished through methods of the [Media](../api/media/index.rst) class, which represents a transmission line object for a given medium. Once constructed, a [Media](../api/media/index.rst) object contains the neccesary properties such as `propagation constant` and `characteristic impedance`, that are needed to generate microwave networks.\n",
    "\n",
    "This tutorial illustrates how created Networks using several different [Media](../api/media/index.rst) objects. The basic usage is, "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "%matplotlib inline\n",
    "import skrf as rf\n",
    "rf.stylely()\n",
    "\n",
    "from skrf import Frequency\n",
    "from skrf.media import CPW\n",
    "\n",
    "freq = Frequency(75,110,101,'ghz')\n",
    "cpw =  CPW(freq, w=10e-6, s=5e-6, ep_r=10.6)\n",
    "cpw"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To create a transmission line of 100um"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "cpw.line(100*1e-6, name = '100um line')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "More detailed examples illustrating how to create various kinds of [Media](../api/media/index.rst) \n",
    "objects are given below. A full list of media's supported can be found in the  [Media](../api/media/index.rst) API page. The network creation and connection syntax of **skrf** are cumbersome  if you need to doing complex circuit design. **skrf**'s synthesis cabilities lend themselves more to scripted applications such as calibration, optimization or batch processing."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##  [Media](../api/media/index.rst) Object Basics \n",
    "\n",
    "Two arguments are common to all media constructors\n",
    "\n",
    "* `frequency` (required)\n",
    "*  `z0`   (optional)\n",
    "\n",
    "`frequency` is  a `Frequency` object, and `z0` is the port impedance. `z0` is only needed if the port impedance is different from the media's characteristic impedance. Here is an example of how to initialize a coplanar waveguide [0] media. The instance has  a 10um center conductor, gap of 5um, and substrate with relative permativity of 10.6,"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "freq = Frequency(75,110,101,'ghz')\n",
    "cpw = CPW(freq, w=10e-6, s=5e-6, ep_r=10.6, z0 =1)\n",
    "\n",
    "cpw"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "For the purpose of microwave network analysis, the defining properties of a (single moded) transmisison line are it's characteristic impedance and propagation constant. These properties return complex `numpy.ndarray`'s,  A *port impedance* is also needed when different networks are connected. \n",
    "\n",
    "The *characteristic impedance* is given by a `Z0` (capital Z)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "cpw.Z0[:3] "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The *port impedance* is given by `z0` (lower z).  Which we set to 1, just to illustrate how this works. The *port impedance* is used to compute impednace mismatched if circuits of different port impedance are connected. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "cpw.z0[:3]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The propagation constant is given by `gamma` "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "cpw.gamma[:3]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Lets take a look at some other [Media](../api/media/index.rst)'s"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Slab of  Si in Freespace\n",
    "\n",
    "A plane-wave in freespace from 10-20GHz."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "from skrf.media import Freespace\n",
    "\n",
    "freq = Frequency(10,20,101,'ghz')\n",
    "air =  Freespace(freq)\n",
    "air"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "air.z0[:2] # 377ohm baby!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# plane wave in Si\n",
    "si = Freespace(freq, ep_r = 11.2)\n",
    "si.z0[:3] # ~110ohm\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Simpulate a 1cm slab of Si in half-space,"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "slab = air.thru() ** si.line(1, 'cm') ** air.thru()\n",
    "slab.plot_s_db(n=0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Rectangular Waveguide\n",
    "\n",
    "a WR-10 Rectangular Waveguide"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "from skrf.media import RectangularWaveguide\n",
    "\n",
    "freq = Frequency(75,110,101,'ghz')\n",
    "wg = RectangularWaveguide(freq, a=100*rf.mil, z0=50) # see note below about z0\n",
    "wg"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The `z0` argument in the Rectangular Waveguide constructor is used\n",
    "to force a specifc port impedance. This is commonly used to match \n",
    "the port impedance to what a VNA stores in a touchstone file. Lets compare the propagation constant in waveguide to that of freespace, "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "air = Freespace(freq)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "from matplotlib import pyplot as plt\n",
    "\n",
    "air.plot(air.gamma.imag, label='Freespace')\n",
    "wg.plot(wg.gamma.imag, label='WR10')\n",
    "\n",
    "plt.ylabel('Propagation Constant (rad/m)')\n",
    "plt.legend()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Because the wave quantities are dynamic they change when the attributes \n",
    "of the media change. To illustrate, plot the propagation constant of the cpw for various values of substrated permativity,  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "for ep_r in [9,10,11]:\n",
    "    cpw.ep_r = ep_r\n",
    "    cpw.frequency.plot(cpw.beta, label='er=%.1f'%ep_r)\n",
    "\n",
    "plt.xlabel('Frequency [GHz]')\n",
    "plt.ylabel('Propagation Constant [rad/m]')\n",
    "plt.legend()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Network Synthesis\n",
    "\n",
    "Networks are created through methods of a Media object. To create a 1-port network for a rectangular waveguide short, "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "wg.short(name = 'short') "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Or to create a $90^{\\circ}$ section of cpw line, "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "cpw.line(d=90,unit='deg', name='line')"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {
    "raw_mimetype": "text/restructuredtext"
   },
   "source": [
    ".. note::\n",
    "\n",
    "\tSimple circuits like :`Media.short` \n",
    "\tand `open` are ideal short and opens with\n",
    "\t$\\Gamma = -1$ and $\\Gamma = 1$, i.e. they dont take \n",
    "\tinto account sophisticated effects of the discontinuties.\n",
    "\tEventually, these more complex networks could be implemented with  \n",
    "    methods specific to a given Media, ie `CPW.cpw_short` , should the need arise...\n",
    "\t"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Building Cicuits\n",
    "\n",
    "\n",
    "By connecting a series of simple circuits, more complex circuits can be \n",
    "made. To build a the $90^{\\circ}$ delay short, in the \n",
    "rectangular waveguide media defined above."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "delay_short = wg.line(d=90,unit='deg') ** wg.short()\n",
    "delay_short.name = 'delay short'\n",
    "delay_short"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "When `Networks` with more than 2 ports need to be connected together, use \n",
    "`rf.connect()`.  To create a two-port network for a shunted delayed open, you can create an ideal 3-way splitter (a 'tee') and conect the delayed open to one of its ports,\n",
    "\t"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "tee = cpw.tee()\n",
    "delay_open = cpw.delay_open(40,'deg')\n",
    "shunt_open = rf.connect(tee,1,delay_open,0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Adding networks in shunt  is pretty common, so there is a `Media.shunt()` function to do this, "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "cpw.shunt(delay_open)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If a specific circuit is created frequently, it may make sense to \n",
    "use a function to create the circuit. This can be done most quickly using `lambda`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "delay_short = lambda d: wg.line(d,'deg')**wg.short()\n",
    "delay_short(90)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A more useful example may be to create a function for a shunt-stub tuner,\n",
    "that will work for any media object"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "def shunt_stub(med, d0, d1):\n",
    "    return med.line(d0,'deg')**med.shunt_delay_open(d1,'deg')\n",
    "\n",
    "shunt_stub(cpw,10,90)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This approach lends itself to design optimization."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Design Optimization\n",
    "\n",
    "\n",
    "The abilities of `scipy`'s optimizers can be used to automate network design. In this example, skrf is used to automate the single stub impedance matching network design. First, we create a 'cost' function which returns somthing we want to minimize, such as the reflection coefficient magnitude at band center. Then, one of scipy's minimization algorithms is used to determine the optimal parameters of the stub lengths to minimize this cost."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "from scipy.optimize import fmin\n",
    "\n",
    "# the load we are trying to match\n",
    "load = cpw.load(.2+.2j)\n",
    "\n",
    "# single stub circuit generator function\n",
    "def shunt_stub(med, d0, d1):\n",
    "    return med.line(d0,'deg')**med.shunt_delay_open(d1,'deg')\n",
    "\n",
    "\n",
    "# define the cost function we want to minimize (this uses sloppy namespace)\n",
    "def cost(d):\n",
    "    # prevent negative length lines, returning high cost\n",
    "    if d[0] <0 or d[1] <0:\n",
    "        return 1e3 \n",
    "    return (shunt_stub(cpw,d[0],d[1]) ** load)[100].s_mag.squeeze()\n",
    "\n",
    "# initial guess of optimal delay lengths in degrees\n",
    "d0 = 120,40 # initial guess\n",
    "\n",
    "#determine the optimal delays\n",
    "d_opt = fmin(cost,(120,40))\n",
    "\n",
    "d_opt "
   ]
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "celltoolbar": "Raw Cell Format",
  "kernelspec": {
   "display_name": "Python [conda env:py35]",
   "language": "python",
   "name": "conda-env-py35-py"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
